package com.gitee.wsl.ext.bitcode

import com.gitee.wsl.lang.ByteOrder
import com.gitee.wsl.lang.isBigEndian
import kotlin.jvm.JvmName
import kotlin.jvm.JvmOverloads

/**
 * Returns the byte at the given [index] in a [Short] starting from the least significant byte.
 *
 * @receiver the [Short] to access
 * @param index the index of the byte to return
 * @param endianness the endianness of the short (defaults to [ByteOrder.BIG_ENDIAN])
 * @return the byte at the given [index]
 */
@JvmOverloads
@JvmName("getByte")
inline fun Short.byte(index: Int, endianness: ByteOrder = ByteOrder.BIG_ENDIAN): Byte = if (endianness.isBigEndian) {
    (toInt() ushr (index shl 3) and 0xFF).toByte()
} else {
    (toInt() ushr ((Short.SIZE_BYTES - 1 - index) shl 3) and 0xFF).toByte()
}

/**
 * Returns the byte at the given [index] in an [Int], starting from the least significant byte.
 *
 * @receiver the [Int] to access
 * @param index the index of the byte to return
 * @param endianness the endianness of the int (defaults to [ByteOrder.BIG_ENDIAN])
 * @return the byte at the given [index]
 */
@JvmOverloads
@JvmName("getByte")
inline fun Int.byte(index: Int, endianness: ByteOrder = ByteOrder.BIG_ENDIAN): Byte = if (endianness.isBigEndian) {
    (this ushr (index shl 3) and 0xFF).toByte()
} else {
    (this ushr ((Int.SIZE_BYTES - 1 - index) shl 3) and 0xFF).toByte()
}



/**
 * Returns the byte at the given [index] in a [Long], starting from the least significant byte.
 *
 * @receiver the [Long] to access
 * @param index the index of the byte to return
 * @param endianness the endianness of the long (defaults to [ByteOrder.BIG_ENDIAN])
 * @return the byte at the given [index]
 */
@JvmOverloads
@JvmName("getByte")
inline fun Long.byte(index: Int, endianness: ByteOrder = ByteOrder.BIG_ENDIAN): Byte = if (endianness.isBigEndian) {
    (this ushr (index shl 3) and 0xFF).toByte()
} else {
    (this ushr ((Long.SIZE_BYTES - 1 - index) shl 3) and 0xFF).toByte()
}

/**
 * Returns the byte at the given [index] in a [Float], starting from the least significant byte.
 *
 * @receiver the [Float] to access
 * @param index the index of the byte to return
 * @param endianness the endianness of the float (defaults to [ByteOrder.BIG_ENDIAN])
 * @return the byte at the given [index]
 */
@JvmOverloads
@JvmName("getByte")
inline fun Float.byte(index: Int, endianness: ByteOrder = ByteOrder.BIG_ENDIAN): Byte =
    toRawBits().byte(index, endianness)

/**
 * Returns the byte at the given [index] in a [Double], starting from the least significant byte.
 *
 * @receiver the [Double] to access
 * @param index the index of the byte to return  endianness the endianness of the number (defaults to [ByteOrder.BIG_ENDIAN])
 * @param endianness the endianness of the double (defaults to [ByteOrder.BIG_ENDIAN])
 * @return the byte at the given [index]
 */
@JvmOverloads
@JvmName("getByte")
inline fun Double.byte(index: Int, endianness: ByteOrder = ByteOrder.BIG_ENDIAN): Byte =
    toRawBits().byte(index, endianness)
